package com.peanut.bosskg.util;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSAUtils {
    /**
     * 摘要加密算法
     */
    public static final String SHA1_WITH_RSA = "SHA1WithRSA";
    /**
     * 字符编码
     */
    public static final String CHARSET_UTF_8 = "UTF-8";


    /**
     * 签名
     *
     * @param content    签名明文
     * @param privateKey 私钥
     * @return 返回签名数据
     * @throws Exception
     */
    public static String sign(String content, String privateKey)
            throws Exception {
        //Base64解码
        byte[] str = Base64Utils.decode(privateKey);
        //PKCS8:描述私钥信息格式(是一种密钥规范)
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(str);
        //KeyFactory:将密钥转换成密钥规范或者将密钥规范转换为密钥
        KeyFactory keyf = KeyFactory.getInstance("RSA");
        //根据私钥生成私钥对象
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);
        //创建指定算法的 Signature 对象,此处为"SHA1WithRSA"
        java.security.Signature signature = java.security.Signature
                .getInstance(SHA1_WITH_RSA);
        //初始化Signature对象
        signature.initSign(priKey);
        //使用指定的 byte 数组更新要签名或验证的数据
        signature.update(content.getBytes(CHARSET_UTF_8));
        //完成签名操作
        byte[] signed = signature.sign();

        return Base64Utils.encodeToString(signed);
    }

    /**
     * 验签
     *
     * @param content
     * @param sign
     * @param public_key
     * @return
     * @throws Exception
     */
    public static boolean verify(String content, String sign, String public_key)
            throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = Base64Utils.decode(public_key);
        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(
                encodedKey));

        java.security.Signature signature = java.security.Signature
                .getInstance(SHA1_WITH_RSA);

        signature.initVerify(pubKey);
        signature.update(content.getBytes(CHARSET_UTF_8));

        boolean isVerifySuccess = signature.verify(Base64Utils.decode(sign));
        return isVerifySuccess;

    }

    /**
     * 商户随机生成密钥对
     */
    public static Map<String, String> genKeyPair() {
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 初始化密钥对生成器，密钥大小为96-1024位
        keyPairGen.initialize(1024, new SecureRandom());
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        try {
            // 得到公钥字符串
            String publicKeyString = Base64.encode(publicKey.getEncoded());
            // 得到私钥字符串
            String privateKeyString = Base64.encode(privateKey.getEncoded());
            Map<String, String> keyMap = new HashMap<>(2);
            keyMap.put("publicKey", publicKeyString);
            keyMap.put("privateKey", privateKeyString);
            System.out.println("商户私钥");
            System.out.println(privateKeyString);
            System.out.println("商户公钥");
            System.out.println(publicKeyString);
            return keyMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param privateKey 私钥
     * @param publicKey  公钥
     * @return 验证结果
     * @throws Exception
     */
    public static boolean checkKey(String content, String privateKey, String publicKey) throws Exception {
        //签名
        String sign = RSAUtils.sign(content, privateKey);
        System.out.println("签名结果：" + sign);
        //验签
        boolean verifyResult = RSAUtils.verify(content, sign, publicKey);
        System.out.println("公私钥验证结果:" + verifyResult);
        return verifyResult;
    }

    public static void main(String[] args) throws Exception {
        /**生成公私钥**/
        Map<String, String> keyPair = RSAUtils.genKeyPair();
        //测试明文
        String content = "HELLO WORLD";
        //私钥
        String privateKey = keyPair.get("privateKey");
        //公钥
        String publicKey = keyPair.get("publicKey");
        /**验证公私钥是否匹配**/
        RSAUtils.checkKey(content, privateKey, publicKey);
    }

}
